package com.example.photo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.photo.common.AuthCheck;
import com.example.photo.common.ErrorCode;
import com.example.photo.constant.ContestGroupNum;
import com.example.photo.constant.WorkStatus;
import com.example.photo.exception.BusinessException;
import com.example.photo.mapper.PrizeMapper;
import com.example.photo.mapper.WorkMapper;
import com.example.photo.model.VO.PrizeVO;
import com.example.photo.model.VO.ScoreWorkVO;
import com.example.photo.model.domain.Prize;
import com.example.photo.model.domain.Work;
import com.example.photo.model.request.add.NewPrizeRequest;
import com.example.photo.model.request.update.UpdatePrizeRequest;
import com.example.photo.service.PrizeService;
import com.example.photo.service.WorkService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 85792
 * @description 针对表【prize(奖项)】的数据库操作Service实现
 * @createDate 2023-03-25 19:15:19
 */
@Service
@Slf4j
public class PrizeServiceImpl extends ServiceImpl<PrizeMapper, Prize>
        implements PrizeService {

    @Resource
    private PrizeMapper prizeMapper;

    @Resource
    private WorkService workService;

    @Resource
    private WorkMapper workMapper;

    /**
     * 创建奖项
     */
    @Override
    public PrizeVO createPrize(NewPrizeRequest newPrizeRequest) {

        Prize prize = new Prize(newPrizeRequest);

        boolean save = this.save(prize);
        if (!save) {
            throw new BusinessException(ErrorCode.SERVER_ERROR, "保存奖项失败");
        }
        return new PrizeVO(prize);
    }

    /**
     * 将奖项关联到赛事
     *
     * @param prizeIds  奖项id列表
     * @param contestId 赛事id
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public void setContestForPrizes(List<Integer> prizeIds, Integer contestId) {
        if (prizeIds.size() == 0 || contestId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        prizeMapper.updateContestId(prizeIds, contestId);
    }

    /**
     * 根据赛事id查询奖项
     */
    @Override
    public List<Integer> getIdsByContestId(Integer contestId) {
        QueryWrapper<Prize> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id", contestId);
        List<Prize> prizes = prizeMapper.selectList(wrapper);
        return prizes.stream().map(Prize::getPrizeId).collect(Collectors.toList());
    }

    /**
     * 更新奖项信息
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public PrizeVO updatePrize(UpdatePrizeRequest updatePrizeRequest) {
        Integer prizeId = updatePrizeRequest.getPrizeId();
        if (prizeId < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        synchronized (("updatePrize" + prizeId).intern()) {
            //试图获取旧的奖项信息
            Prize oldPrize = this.getById(prizeId);
            if (oldPrize == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "该奖项不存在");
            }
            //判断是否修改 获奖名额
            Integer newTotalNum = updatePrizeRequest.getTotalNum();
            Integer oldTotalNum = oldPrize.getTotalNum();
            if (newTotalNum > 0 &&
                    !Objects.equals(oldTotalNum, newTotalNum)) {
                //判断修改后的剩余名额是否合法
                int newVacantNum = oldPrize.getVacantNum() + (newTotalNum - oldTotalNum);
                if (newVacantNum < 0) {
                    throw new BusinessException(ErrorCode.PARAMS_ERROR, "修改后剩余名额为负数");
                }
                //修改总名额和剩余名额
                Prize newPrize = new Prize();
                newPrize.setPrizeId(prizeId);
                newPrize.setTotalNum(newTotalNum);
                newPrize.setVacantNum(newVacantNum);
                int update = prizeMapper.updateById(newPrize);
                if (update < 1) {
                    throw new BusinessException(ErrorCode.SERVER_ERROR, "修改奖项名额失败");
                }
            }
            //名额字段置为空
            updatePrizeRequest.setTotalNum(null);
            //更新奖项信息
            int update = prizeMapper.updateById(new Prize(updatePrizeRequest));
            if (update < 1) {
                throw new BusinessException(ErrorCode.SERVER_ERROR, "修改奖项信息失败");
            }
        }
        //重新获取奖项信息并返回
        return new PrizeVO(prizeMapper.selectById(prizeId));
    }

    /**
     * 查询某个赛事下所有作品，包含均分
     *
     * @param pageSize
     * @param pageNum
     * @param contestId 赛事id
     * @return 包含作品均分的作品信息列表
     */
    @AuthCheck
    @Override
    public List<ScoreWorkVO> listToPrize(long pageSize, long pageNum, Integer contestId) {
        //根据赛事id查询所有作品
        QueryWrapper<Work> workQueryWrapper = new QueryWrapper<>();
        workQueryWrapper.eq("contest_id", contestId);
        workQueryWrapper.eq("is_pass", WorkStatus.PASS);
        List<Work> workList = workService.page(new Page<>(pageNum, pageSize), workQueryWrapper).getRecords();
        //当前赛事无已通过审核的作品
        if (workList.size() == 0) {
            return new ArrayList<>();
        }

        return workList.stream().map(ScoreWorkVO::new)
                .peek(scoreWorkVO -> {
                    Integer prizeId = scoreWorkVO.getPrizeId();
                    Prize prize = prizeMapper.selectById(prizeId);
                    if (prize != null) {
                        String prizeName = prize.getPrizeName();
                        scoreWorkVO.setPrizeName(prizeName);
                    }
                })
                .collect(Collectors.toList());
    }

    /**
     * 查询作品可以获得的奖项
     *
     * @param workId 作品id
     * @return 奖项信息列表
     */
    @Override
    public List<PrizeVO> getPrizes(Integer workId) {
        Work work = workService.getById(workId);
        Integer contestId = work.getContestId();
        Integer contestGroup = work.getContestGroup();
        QueryWrapper<Prize> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id", contestId);
        wrapper.eq("contest_group", contestGroup);
        List<Prize> prizes = prizeMapper.selectList(wrapper);
        if (prizes.size() == 0) {
            return new ArrayList<>();
        }
        return prizes.stream().map(PrizeVO::new).collect(Collectors.toList());
    }

    /**
     * 给作品颁奖（重复颁奖会修改）
     *
     * @param workId  作品id
     * @param prizeId 奖项id
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public synchronized void conferPrize(Integer workId, Integer prizeId) {
        Prize prize = prizeMapper.selectById(prizeId);
        if (prize == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "该奖项不存在");
        }
        //判断是否有剩余名额
        Integer vacantNum = prize.getVacantNum();
        if (vacantNum > 0) {
            Work work = workMapper.selectById(workId);
            if (work == null) {
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "该作品不存在");
            }
            if (work.getIsPass() == WorkStatus.NO_EXAMINE || work.getIsPass() == WorkStatus.BACK) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前作品尚未通过审核");
            }

            //更新作品的奖项id字段
            workMapper.setPrize(workId, prizeId);

            //更新奖项的剩余人数字段
            Integer oldPrizeId = work.getPrizeId();
            if (oldPrizeId != 0) {
                //原本已有奖项
                prizeMapper.incrementVacantNum(oldPrizeId);
            }
            prizeMapper.decrementVacantNum(prizeId);
        } else {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前奖项已无剩余名额");
        }
    }

    /**
     * 撤销颁奖
     *
     * @param workId 作品id
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    @Override
    public synchronized void withdrawalPrize(Integer workId) {
        Work work = workMapper.selectById(workId);
        if (work == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "该作品不存在");
        }
        Integer prizeId = work.getPrizeId();
        if (prizeId == 0) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "该作品未获奖");
        }
        //作品奖项字段置为0
        workMapper.setPrize(workId, 0);

        //奖项剩余名额增加1
        prizeMapper.incrementVacantNum(prizeId);
    }

    /**
     * 根据赛事id获取其所有的奖项，并按照奖项所属组分组
     *
     * @param contestId 赛事id
     * @return 已所属组编号为键，奖项信息列表为值的map
     */
    @Override
    public Map<Integer, List<PrizeVO>> getPrizesByContestId(Integer contestId) {
        QueryWrapper<Prize> wrapper = new QueryWrapper<>();
        wrapper.eq("contest_id", contestId);
        List<Prize> prizeList = prizeMapper.selectList(wrapper);
        //当前赛事无奖项，返回空map
        if (prizeList.size() == 0) {
            return new HashMap<>();
        }
        //根据所属组分类
        Map<Integer, List<PrizeVO>> map = new HashMap<>();
        map.put(ContestGroupNum.CAMERA, new ArrayList<>());
        map.put(ContestGroupNum.PHONE, new ArrayList<>());
        map.put(ContestGroupNum.VIDEO, new ArrayList<>());
        map.put(ContestGroupNum.AI, new ArrayList<>());
        for (Prize prize : prizeList) {
            Integer contestGroup = prize.getContestGroup();
            if (contestGroup < 1 || contestGroup > 4) {
                log.info("id为[" + prize.getPrizeId() + "]的奖项拥有非法的所属组编号：[" + contestGroup + "]");
                continue;
            }
            map.get(contestGroup).add(new PrizeVO(prize));
        }
        return map;
    }
}




